/*
Copyright 2011 Mary Suárez Machado

Este programa es de software libre: usted puede redistribuirlo y/o modificarlo según los términos de la Licencia de Gran pública de GNU como publicado por la Fundación de Software Libre, versión 3 de la Licencia, (o en su opción) cualquier versión posterior.

 Este programa es distribuido en la esperanza que será útil, pero SIN CUALQUIER GARANTÍA; sin aún la garantía implícita de VALOR COMERCIAL O SALUD PARA UN OBJETIVO PARTICULAR. Mirar la Licencia de Gran pública de GNU para más detalles.
*/


 /**
 *@file mp2gzip.cpp
 *@brief Programa principal que resuelve la codificación de un texto
 *@author Mary Carmen Suarez
 *
 */

#include <iostream>
#include <fstream>
#include <cstring>
#include <TablaLongitud.h>
#include <TablaDistancia.h>
#include <VectorBits.h>
#include <TablaHuffmanD.h>
#include <TablaHuffmanLC.h>
#include <crc.h>
#include <LZcoder.h>

using namespace std;

//El programa recibe desde la linea de ordenes (opcionalmente -mejor) el nombre del archivo a comprimir (opcionalmente el nombre destino)

int main(int argc, char * argv[])
{
	//El minimo de argumentos 2 y el maximo 4
	if (argc != 2 && argc != 3 && argc != 4)
	{
		cerr << "El numero de argumentos no es correcto" << endl;
		return -1;
	}
	
	//Declaracion de variables

	TablaLongitud tl;
	TablaDistancia td;
	TablaHuffmanD hd;
	TablaHuffmanLC hl;
	VectorBits v;
	LZcoder coder;

	//Preparacion de los argumentos de entrada

	bool mejor=false;
	char * ent=0;
	char * sal=0;
	//Si se pone como argumento -mejor el fichero de entrada es argv[2] y el fichero de salida es argv[3]
	if ( ! strcmp(argv[1],"-mejor") )
	{
		mejor=true;
		ent = new char [strlen(argv[2]) +1];
		strcpy (ent,argv[2]);
		if (argc == 4)
		{
			sal = new char [strlen(argv[3])+1];
			strcpy(sal,argv[3]);
		}
		else sal=0;
	}
	//Si no se pone ese argumento el fichero de entrada es argv[1] y el fichero de salida es argv[2]
	else
	{
		ent = new char [strlen(argv[1]) +1];
		strcpy (ent,argv[1]);
		if (argc == 3)
		{
			sal = new char [strlen(argv[2])+1];
			strcpy(sal,argv[2]);
		}
		else sal=0;
	}

	//Inicializamos la variable f (fichero de entrada) con ent
	ifstream f(ent);
	if ( !f ) //Si el fichero no lo hemos podido cargar bien...
	{
		cerr << "El fichero no se pudo abrir" << endl;
		return -1; //... el programa acaba
	}
	//Declaramos la variable fs (fichero de salida)
	ofstream fs;
	if (sal != 0) //Si se ha indicado el nombre destino...
	{
		fs.open(sal); //inicializamos la variable fs con sal
		if ( !fs ) //Si hay algun problema con el fichero...
		{
			cerr << "Fichero de  salida no se puede abrir" << endl;
			return -1; //... el programa acaba
		}
	}
	else //Le ponemos como nombre de destino el mismo que la entrada pero acabado en .gz
	{
		int tam = strlen(ent);
		char * salida = new char [tam+4];
		strcpy(salida, ent);
		strcat(salida,".gz");
		fs.open(salida); //inicializamos la variable fs con salida
		delete [] salida;
		if ( !fs ) //Si hay algún problema con el fichero...
		{
			cerr << "Fichero de  salida no se puede abrir" << endl;
			return -1; //... el programa acaba
		}

	}

	// Cabecera de fichero
	char cabecera[] = {0x1F,0x8B,0x08,0x18,0x00,0x00,0x00,0x00,0x04,0xFF};
	fs.write(cabecera,10);
	// Nombre del fichero original
	fs.write(ent,strlen(ent)+1);
	// Comentario (nombre del alumno y su DNI)
	char nombre[] = "Mary Suarez Machado 76626643-G";
	fs.write(nombre,strlen(nombre)+1);
	// Cabecera compuesta por los bits 110
	v += 1;
	v += 1;
	v += 0;
	//Lectura del fichero
	coder.Leer(f);

	int dato = 0;
	//Compresión del fichero
	while (dato != 256)
	{
		if (mejor == true)
			dato = coder.SiguienteCodigoMejor(); //Utiliza el algoritmo mejorado
		else 	dato = coder.SiguienteCodigo(); //Utiliza el normal
		if (dato <= 256){
			VectorBits ve;
			ve=hl.GetCodificacion(dato);
			v += hl.GetCodificacion(dato);
		}
		if (dato > 256)
		{
			int cod = tl.GetCodigo(dato-256);
			v += hl.GetCodificacion(cod);
			v += tl.GetBitsAdicionales(dato-256);
			int dis = coder.GetDistancia();
			int cod_dist = td.GetCodigo(dis);
			v += hd.GetCodificacion(cod_dist);
			v += td.GetBitsAdicionales(dis);
		}
	}
	//Escritura en el fichero de salida todo el fichero de entrada comprimido
	v.Salvar(fs);

	//Calculo del crc32 (fichero sin comprimir)
	unsigned int crc = coder.GetParidad();
	//Calculo del tamaño del fichero sin comprimir
	unsigned int tam = coder.GetTamano();

	//Escritura del crc32
	fs.write( (char*)&crc, 4);	
	//Escritura del tamaño del fichero sin comprimir
	fs.write( (char*)&tam, 4);	
}
